/* 
 * File:   JAdapterThread.cpp
 * Author: johnneyshi
 * 
 * Created on 2013年3月4日, 上午9:43
 */

#include "JAdapterThread.h"
#include "JServerMaster.h"
#include "JDefine.h"
#include <string.h>
#include <algorithm>
#include "JServerMaster.h"
#include "JException.h"
#include <sys/syscall.h>
#include "JLog.h"

#define gettid() syscall(__NR_gettid)

JAdapterThread::JAdapterThread(AdapterThreadArg* _pArg) : pArg(_pArg),toMasterConnFd(-1),toWorkerConnFd(-1)
{
    epoll.Create(2);//一个toWorkerConnFd和toMasterConnFd
}


void JAdapterThread::GetToMasterConnFd()
{
    std::queue<int>& needDealFds = pArg->pMaster->needDealFds;
    //printf("adapter thread this:%x\n",pArg->pMaster);
    toMasterConnFd = -1;
    pthread_mutex_lock(&(JServerMaster::needDealFdsLock));
    JLog::Log(JLogMessage,"wait begin\n");
    while(needDealFds.empty())
    {
        //JLog::Log(JLogMessage,"need deal fds empty\n");
        //printf("add:%x\n",&needDealFds);
        pthread_cond_wait(&(JServerMaster::needDealFdsCond),&(JServerMaster::needDealFdsLock));
    }
    JLog::Log(JLogMessage,"wait end\n");
    toMasterConnFd = needDealFds.front();
    needDealFds.pop();
    pthread_mutex_unlock(&(JServerMaster::needDealFdsLock));
    
    JLog::Log(JLogMessage,"Adapter thread get fd:%d\n",toMasterConnFd);
    //设置位non_block
    JServer::SetNonBlock(toMasterConnFd);
}

void JAdapterThread::ConnectToWorker()
{
    //如果port==0，自动分配
    if(pArg->port == 0)
    {
        
    }
    else
    {
        client.Bind(pArg->pAdapter->pClient->GetClientIP(),pArg->port);
    }
    //捕获可能端口被占用，那么就自动分配端口
    try{
        JLog::Log(JLogMessage,"Thread:%d client(%s,%d) try to connect to server:(%s,%d)\n",gettid(),pArg->pAdapter->pClient->GetClientIP().c_str(),pArg->port,pArg->pAdapter->worker.ip.c_str(),pArg->pAdapter->worker.port);
        client.Connect(pArg->pAdapter->worker.ip,pArg->pAdapter->worker.port);
        JLog::Log(JLogMessage,"Connect success");
    }catch(JException& e)
    {
        client.Bind("",0);
        client.Connect(pArg->pAdapter->worker.ip,pArg->pAdapter->worker.port);
        JLog::Log(JLogMessage,"Thread:%d client(zidongfenpei)connect to server:(%s,%d)\n",gettid(),pArg->pAdapter->worker.ip.c_str(),pArg->pAdapter->worker.port);
    }
    toWorkerConnFd = client.GetConnFd();
    //设置位non_block
    JServer::SetNonBlock(toWorkerConnFd);
}

int JAdapterThread::TransmitMsg()
{
    int n = -1;
    char buff[BUFF_SIZE];
    JLog::Log(JLogMessage,"Wait begin\n");
    std::vector<int> fds = epoll.Wait();
    JLog::Log(JLogMessage,"Wait end\n");
    for(int i = 0;i < fds.size(); ++i)
    {
        //master向worker发送数据,也就是客户端向worker发送数据
        if(fds[i] == toMasterConnFd)
        {
            while((n = read(toMasterConnFd,buff,BUFF_SIZE)) > 0)
            {
                buff[n] = '\0';
                JLog::Log(JLogMessage,"master to worker:%s\n",buff);
                write(toWorkerConnFd,buff,n);
            }
            //断开
            if(n == 0)
            {
                return toMasterConnFd;
            }
            //没有数据可读
            else if(n == -1)
            {
                
            }
        }
        //worker向master发送数据
        else if(fds[i] == toWorkerConnFd)
        {
            while((n = read(toWorkerConnFd,buff,BUFF_SIZE)) > 0)
            {
                buff[n] = '\0';
                JLog::Log(JLogMessage,"worker to master:%s\n",buff);
                write(toMasterConnFd,buff,n);
            }
            //断开
            if(n == 0)
            {
                return toWorkerConnFd;
            }
            //没有数据可读
            else if(n == -1)
            {
                
            }
        }
    }
    
}
/*
 * 这里还需要一种机制：如果客户端拒绝攻击，或者发送的数据没有到size大小，那么就循环，从队列中另外再取一个描述符，进行处理
 * 但是原来的描述符，也用epoll监听着，最后只有接受到size大小的数据，才发往worker
 */
void JAdapterThread::Start()
{
    JLog::Log(JLogMessage,"pid:%d,Create tid:%d\n",getpid(),gettid());
    while(true)
    {
        if(toWorkerConnFd == -1)
        {
            ConnectToWorker();//得到了toWorkerConnFd
            epoll.AddFd(toWorkerConnFd,EPOLLIN);
        }
        if(toMasterConnFd == -1)
        {
            GetToMasterConnFd();//得到了toMasterConnFd
            epoll.AddFd(toMasterConnFd,EPOLLIN);
        }
        int fd = TransmitMsg();
        //客户端断开
        if(fd == toMasterConnFd)
        {
            JLog::Log(JLogMessage,"Delete master fd:%d\n",fd);
            int a = -1;
            JLog::Log(JLogMessage,"Adapter delete pipe:%d write to fd:%d\n",fd,pArg->childWritePipe);
            write(pArg->childWritePipe,(void*)&a,SIZEOF_INT);
            epoll.DeleteFd(toMasterConnFd);
            close(toMasterConnFd);
            toMasterConnFd = -1;
        }
        //与worker的连接断开
        else if(fd == toWorkerConnFd)
        {
            JLog::Log(JLogMessage,"Delete worker fd:%d\n",fd);
            epoll.DeleteFd(toWorkerConnFd);
            close(toWorkerConnFd);
            toWorkerConnFd = -1;
        }
    }
}

JAdapterThread::~JAdapterThread() 
{
}

